/**
 *
 * yytStorage - - localStorage工具
 * @author caiwc 277600202@qq.com
 * @date 2017-08-01
 *
 * 如果有支持localStorage则使用localStorage
 * 如果没有支持localStorage且支持userData 则使用userData
 *
 * 代码支持 CommonJS, AMD, global(window)环境下运行
 */

(function(root, factory) {

    'use strict';

    if (typeof define === 'function' && define.amd) {
        define(factory);
    } else if (typeof exports !== 'undefined') {
        module.exports = factory();
    } else {
        root.yytStorage = factory();
    }

}(this, function() {

    /**
     * 判断是否支持localStorage
     * @return {*}
     */
    function isLocalStorageValid() {
        try {
            return typeof localStorage !== 'undefined' &&
                ('setItem' in localStorage) &&
                localStorage.setItem;
        } catch (e) {
            return false;
        }
    }

    /**
     * 实现基于IE的userData存储
     * @constructor
     */
    function UserDataStorage() {

        var keys = {};

        var memory = document.createElement("div");
        memory.style.display = "none";
        memory.style.behavior = "url('#default#userData')"; // 附加userData行为
        document.body.appendChild(memory);

        memory.load("UserDataStorage");

        // 提示userdata并不支持事件
        var consoleWarn = function(funname) {
            if (console && console.warn) console.warn("this browser storage is not support " + funname + " function.");
        };

        this.setItem = function(key, value) {
            memory.setAttribute(key, value); // 以设置属性的形式保存数据
            memory.save("UserDataStorage"); // 保存数据改变后的状态
            keys[key] = 1; //  保存key, 在clear的时候能用上
        };

        this.getItem = function(key) {
            return memory.getAttribute(key) || null;
        };

        this.removeItem = function(key) {
            memory.removeAttribute(key);
            memory.save("UserDataStorage");
            keys[key] = null;
        };

        this.clear = function() {
            consoleWarn("clear");

            for (var key in keys) {
                if (keys[key]) {
                    memory.removeAttribute(key);
                }
            }
            memory.save("UserDataStorage");
        }
    }

    Array.prototype.removeByValue = function(val) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == val) {
                this.splice(i, 1);
                break;
            }
        }
    };

    // storage api ========================================

    // storage
    var Storage = null;
    if (isLocalStorageValid()) {
        Storage = localStorage;
    } else {
        Storage = new UserDataStorage();
    }

    // 键值改变事件
    var events = {};

    /**
     * 设置键值对
     * @param key
     * @param value
     */
    var setItem = function(key, value) {
        var oldValue = Storage.getItem(key);
        oldValue = oldValue ? decodeURIComponent(oldValue) : oldValue;
        Storage.setItem(key, value ? encodeURIComponent(value) : value);
        fireEvents({
            key: key,
            oldValue: oldValue,
            newValue: value
        });
    };

    /**
     * 移除缓存
     * @param key
     */
    var removeItem = function(key) {
        var oldValue = Storage.getItem(key);
        oldValue = oldValue ? decodeURIComponent(oldValue) : oldValue;
        Storage.removeItem(key);
        fireEvents({
            key: key,
            oldValue: oldValue,
            newValue: null
        });
    };

    /**
     * 清空存储
     */
    var clear = function() {
        Storage.clear();
        fireEvents({
            key: null,
            oldValue: null,
            newValue: null
        });
    };

    /**
     * 根据键获取值
     * @param key
     */
    var getItem = function(key) {
        var oldValue = Storage.getItem(key);
        oldValue = oldValue ? decodeURIComponent(oldValue) : oldValue;
        return oldValue;
    };

    /**
     * 拼接storage, connect默认,
     * @param key
     * @param value
     */
    var itemAppend = function(key, value, split) {
        split = split ? split : ",";
        var oldValue = getItem(key);
        if (oldValue) {
            setItem(key, oldValue + split + value);
        } else {
            setItem(key, value);
        }
    };

    var itemSplice = function(key, value, split) {
        split = split ? split : ",";
        var oldValue = getItem(key);
        if (oldValue) {
            var arr = oldValue.split(split);

            var newList = [];
            for (var i = 0; i < arr.length; i++) {
                if (arr[i] != value) {
                    newList.push(arr[i]);
                }
            }
            setItem(key, newList.join(split));
            return value;
        }
        return null;
    };

    /**
     * 增加监听
     * @param key
     * @param callback
     */
    var addEventListener = function(key, callback) {
        if (!events[key]) events[key] = [];
        if (typeof callback == 'function')
            events[key].push(callback);
    };

    /**
     * 移除监听
     * @param key
     * @param callback
     */
    var removeEventListener = function(key, callback) {
        if (events[key])
            events[key].removeByValue(callback);
    };

    // 触发监听
    var fireEvents = function(e) {
        var key = e.key;
        var oldValue = e.oldValue;
        var newValue = e.newValue;

        if (key) {
            if (events[key]) {
                for (var i = 0; i < events[key].length; i++) {
                    events[key][i].call(this, {
                        key: key,
                        oldValue: oldValue,
                        newValue: newValue
                    });
                }
            }
        } else {
            for (var j in events) {
                for (var i = 0; i < events[j].length; i++) {
                    events[j][i].call(this, {
                        key: null,
                        oldValue: null,
                        newValue: null
                    });
                }
            }
        }

    };

    if (window.addEventListener) {
        window.addEventListener('storage', fireEvents, false);
    } else {
        window.attachEvent("onstorage", fireEvents);
    }

    return {

        itemAppend: itemAppend,

        itemSplice: itemSplice,

        setItem: setItem,

        getItem: getItem,

        removeItem: removeItem,

        clear: clear,

        addEventListener: addEventListener,

        removeEventListener: removeEventListener
    };
}));